﻿using Microsoft.VisualStudio.GraphModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Timtopia.DGMLPosterView
{
    public class PhrasenetsDecomposition
    {
        public static void Apply(Graph graph)
        {
            using (var scope = new GraphTransactionScope())
            {
                var neighborLists = new Dictionary<string, List<GraphNode>>();
                var completeNeighbourLists = new Dictionary<string, List<GraphNode>>();
                foreach (var v in graph.Nodes)
                {
                    var incoming = new List<string>();
                    var outgoing = new List<string>();

                    foreach (var u in v.IncomingLinks.Where(l => !l.HasCategory(GraphCommonSchema.Contains)))
                    {
                        incoming.Add(u.Source.Id.ToString());
                    }
                    foreach (var w in v.OutgoingLinks.Where(l => !l.HasCategory(GraphCommonSchema.Contains)))
                    {
                        outgoing.Add(w.Target.Id.ToString());
                    }
                    incoming.Sort();
                    outgoing.Sort();
                    Func<string, string, string> acc = (a, s) => a + "," + s;
                    string neighboursString =
                        (incoming.Any() ? incoming.Aggregate(acc) : "")
                        + "|"
                        + (outgoing.Any() ? outgoing.Aggregate(acc) : "");
                    List<GraphNode> neighbours;
                    if (!neighborLists.TryGetValue(neighboursString, out neighbours))
                    {
                        neighbours = new List<GraphNode>();
                        neighborLists.Add(neighboursString, neighbours);
                    }
                    neighbours.Add(v);

                    incoming.Add(v.Id.ToString());
                    incoming.Sort();
                    outgoing.Add(v.Id.ToString());
                    outgoing.Sort();
                    neighboursString = neighboursString =
                        (incoming.Any() ? incoming.Aggregate(acc) : "")
                        + "|"
                        + (outgoing.Any() ? outgoing.Aggregate(acc) : "");
                    if (!completeNeighbourLists.TryGetValue(neighboursString, out neighbours))
                    {
                        neighbours = new List<GraphNode>();
                        completeNeighbourLists.Add(neighboursString, neighbours);
                    }
                    neighbours.Add(v);
                }
                int groupCounter = 0;
                foreach (var vs in neighborLists.Values.Where(l => l.Count > 1))
                {
                    var g = graph.Nodes.GetOrCreate("group" + groupCounter++);
                    g.IsGroup = true;
                    foreach (var v in vs)
                    {
                        var l = graph.Links.GetOrCreate(g, v);
                        l.AddCategory(GraphCommonSchema.Contains);
                    }
                }

                groupCounter = 0;
                foreach (var vs in completeNeighbourLists.Values.Where(l => l.Count > 1))
                {
                    var g = graph.Nodes.GetOrCreate("complete" + groupCounter++);
                    g.IsGroup = true;
                    foreach (var v in vs)
                    {
                        var l = graph.Links.GetOrCreate(g, v);
                        l.AddCategory(GraphCommonSchema.Contains);
                    }
                }
                scope.Complete();
            }
        }
    }
}
